#ifndef YTESTNULLPTR_H
#define YTESTNULLPTR_H
#include <cstddef>
#include <iostream>
using namespace std;

//防止修改mynullptr的值
const class mynullptr_t{
    public:

    /*operator的两种用法
    *1.操作符重载
      形式为: 返回值类型  operator 操作符();
      解析为: 函数三要素:返回值类型[返回值类型];函数名[operator 操作符];形参列表[()]
     2.类型隐式转换
      形式为: operator 转换类型();
      解析为:函数三要素:返回值类型就是转换类型所以避免冲突不需要;函数名为[operator 转换类型];形参列表[()]
    */
    //转为普通型的指针类型
    template<typename T>
    inline operator T*() const{
        cout<<"operator T* call"<<endl;
        return 0;
    }


    /*1.定义指向类成员变量的指针类型
      形式为: 指向类型 类名::*指针变量 = &类名::类成员变量名
      解析为: int     A::*p          = &A::a; [使用下面的class A]做为例子
      解引用: 类对象.*指针变量
      2.定义指向类成员函数的指针类型
      形式为: 指向类型 (类名::*指针变量)(形参列表类型) = &类名::类成员函数名
      解析为: void     (A::*pf)()                   = &A::print;
      解引用:类对象.*指针变量    
      */
    //转为类成员变量或函数的指针类型
    template<class C, typename T>
    inline operator T C::*() const{
        cout<<"operator T C::* call"<<endl;
        return 0;
    } 
private:
    //取消取地址操作
    void operator&() const;

}mynullptr = {};

class A{
 public:
    A(int ma,float mb, int *md):a(ma),b(mb),d(md)
    {

    }
    void print()
    {
        cout<<"a:"<<a<<"\t"<<b<<"\t"<<c<<"\t"<<*d<<endl;
    }
public:
    int a;
    float b;
    static int c;
    int *d;
};
int A::c = 10;
void testNullPtr()
{
    //测试指向类成员变量和类成员函数的指针
    int A::*pa = &A::a;
    int* A::*pd = &A::d;
    void (A::*fp)() = &A::print;

    int md = 11;
    A ca(8,9.9,&md);

    cout<<"/////////////////////////////////成员指针/////////////////////////////////////"<<endl;
    cout<<"输出地址信息：";
    cout<<"pa:"<<pa<<"\t"<<pd<<"\t"<<fp<<endl;
    cout<<"输出内容:";
    ca.print();

    cout<<ca.*pa<<"\t"<<*(ca.*pd)<<endl;
    (ca.*fp)();
    cout<<A::c<<endl;

    cout<<"/////////////////////////////////null指针/////////////////////////////////////"<<endl;

    mynullptr_t mynullptr0;
    std::nullptr_t nullptr0 = nullptr;
    int *a = 0;
    int *b = NULL;
    int *c = nullptr;
    int *d = mynullptr;
    int *e = nullptr0;
    int *f = mynullptr0;
    cout<<a<<"\t"<<b<<"\t"<<c<<"\t"<<d<<"\t"<<e<<"\t"<<f<<endl;

    int A::*la = mynullptr0;
    double A::*lb = nullptr;
    void (A::*lc)() = mynullptr;
    cout<<la<<"\t"<<lb<<"\t"<<lc<<endl;

}
#endif